Skip to content

Personal copy of anomalyco/opencode#29208: fix(config): catch parse errors gracefully during startup#4

Open
HaleTom wants to merge 32 commits into
devfrom
json-errors
Open

Personal copy of anomalyco/opencode#29208: fix(config): catch parse errors gracefully during startup#4
HaleTom wants to merge 32 commits into
devfrom
json-errors

Conversation

@HaleTom
Copy link
Copy Markdown
Owner

@HaleTom HaleTom commented May 25, 2026

Personal copy of anomalyco/opencode#29208

HaleTom added 4 commits May 25, 2026 18:41
Wrap ConfigParse.jsonc() and ConfigParse.effectSchema() calls in
loadConfig with Effect.catchCause to prevent sync-thrown JsonError
and InvalidError from becoming Effect defects. On parse/schema
failure, the bad file is skipped with a log.error and {} fallback
instead of crashing, matching the existing tui.jsonc error handling
pattern in tui.ts.

Without this, any invalid JSONC syntax or schema violation in
opencode.json/opencode.jsonc causes "4 of 6 requests failed:
Unexpected server error" on startup. Now the server starts with
default values and logs the config error details.

Fixes anomalyco#29200
Copilot AI review requested due to automatic review settings May 25, 2026 16:02
@semanticdiff-com
Copy link
Copy Markdown

semanticdiff-com Bot commented May 25, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  packages/opencode/src/config/config.ts  18% smaller
  packages/opencode/test/config/config.test.ts  10% smaller

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@github-actions
Copy link
Copy Markdown

Hey! Your PR title Personal copy of anomalyco/opencode#29208: fix(config): catch parse errors gracefully during startup doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

@github-actions
Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant architectural shift and UI overhaul across the OpenCode platform. Key updates include migrating the desktop application from Tauri to Electron, implementing a new tab-based navigation and composer design for non-production environments, and adding a referral reward system to the console. The codebase underwent a major refactoring to rename global SDK and sync providers to server-specific contexts, alongside infrastructure updates to monitoring and deployment regions. Review feedback highlights a critical accessibility concern regarding hidden streaming content, warns against breaking changes in custom provider configurations due to consolidated placeholders, and recommends using reactive state over direct DOM access in the prompt input component.

Comment thread packages/app/src/pages/session/message-timeline.tsx
Comment thread packages/console/app/src/routes/zen/util/handler.ts
Comment thread packages/app/src/components/prompt-input.tsx
@HaleTom
Copy link
Copy Markdown
Owner Author

HaleTom commented May 25, 2026

@gemini-code-assist please

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

packages/opencode/src/config/config.ts:446

  • When config parsing/schema decoding fails, data falls back to an empty decoded Info, but the function still proceeds to the $schema auto-injection block. This can overwrite an invalid config file (or duplicate an existing $schema key) even though the file couldn't be parsed/validated, which is potentially destructive and can further corrupt the user's config.

Consider short-circuiting on parse/validation failure (e.g., return early for path sources) or tracking a parsedSuccessfully flag so plugin resolution and $schema auto-write only run when parsing/validation succeeded.

      const data = yield* Effect.sync(() => {
        const parsed = ConfigParse.jsonc(expanded, source)
        return ConfigParse.schema(Info, normalizeLoadedConfig(parsed, source), source)
      }).pipe(
        Effect.catchCause((cause) =>
          Effect.sync(() => {
            log.error("invalid config", { path: source, cause })
            return Schema.decodeSync(Info)({})
          }),
        ),
      )
      if (!("path" in options)) return data

      yield* Effect.promise(() => resolveLoadedPlugins(data, options.path)).pipe(
        Effect.catchCause((cause) =>
          Effect.sync(() => {
            log.error("plugin resolution failed", { path: source, cause })
          }),
        ),
      )
      if (!data.$schema) {
        data.$schema = "https://opencode.ai/config.json"
        const updated = text.replace(/^\s*\{/, '{\n  "$schema": "https://opencode.ai/config.json",')
        yield* fs.writeFileString(options.path, updated).pipe(Effect.catch(() => Effect.void))

@gemini-code-assist
Copy link
Copy Markdown

The implementation for graceful error handling using Effect.catchCause is well-structured and aligns with the Effect ecosystem. The added tests cover the necessary edge cases.

One minor suggestion:

In packages/opencode/src/config/config.ts, verify that your log.error implementation correctly serializes the cause object. If it's a standard logger, you might want to ensure it doesn't lose stack trace information or error details, which could be critical for debugging configuration issues.

Severity: low

@HaleTom
Copy link
Copy Markdown
Owner Author

HaleTom commented May 25, 2026

@gemini-code-assist

@HaleTom
Copy link
Copy Markdown
Owner Author

HaleTom commented May 25, 2026

@gemini-code-assist pls

@gemini-code-assist
Copy link
Copy Markdown

The implementation of the parsedOk flag effectively prevents $schema injection on invalid configurations, and the new test cases in packages/opencode/test/config/config.test.ts provide excellent coverage for these edge cases. The logic is sound and robust. No further issues found.

1 similar comment
@gemini-code-assist
Copy link
Copy Markdown

The implementation of the parsedOk flag effectively prevents $schema injection on invalid configurations, and the new test cases in packages/opencode/test/config/config.test.ts provide excellent coverage for these edge cases. The logic is sound and robust. No further issues found.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread packages/opencode/src/config/config.ts
Comment thread packages/opencode/src/config/config.ts
@HaleTom
Copy link
Copy Markdown
Owner Author

HaleTom commented May 25, 2026

Addressed the log sanitization suggestion: replaced Cause.pretty(cause) for the log extra — preserves full error chain and stack trace info (via Cause.pretty) without JSON-stringifying the entire Cause<never> object (which embeds expanded config text). Follows the existing pattern in packages/core/src/effect/logger.ts:43.

- Use safe fallback for Info decode ({} as Info) instead of Schema.decodeSync
- Use Cause.pretty for plugin resolution error logging
- Strengthen test assertion with specific value
@HaleTom
Copy link
Copy Markdown
Owner Author

HaleTom commented May 25, 2026

Review 4358274911 is a duplicate of review 4358240107 — both comments were already addressed and resolved:

  1. Leaky logs → fixed with Cause.pretty(cause) for safe serialization
  2. PR scope → explained as fork base divergence, not actual PR changes

No new actionable items here.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment thread packages/opencode/src/config/config.ts
Comment thread packages/opencode/src/config/config.ts Outdated
Comment thread packages/opencode/src/config/config.ts
Comment thread packages/opencode/test/config/config.test.ts
HaleTom added 2 commits May 26, 2026 01:58
- Strip unknown config keys before schema validation to preserve valid fields
- Sanitize log.error calls to avoid leaking config content via cause
- Handle plugin resolution per-item to avoid partial mutation on failure
- Add test for plugin resolution failure
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread packages/opencode/src/config/config.ts Outdated
Comment thread packages/opencode/src/config/config.ts Outdated
Comment thread packages/opencode/src/config/config.ts
@github-actions
Copy link
Copy Markdown

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

Feel free to open a new pull request that follows our guidelines.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Re-trigger cubic

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment on lines +76 to +82
function stripUnknownKeys(data: unknown): unknown {
if (typeof data !== "object" || data === null || Array.isArray(data)) return data
const known = new Set(Info.ast.propertySignatures.map((p) => String(p.name)))
const result: Record<string, unknown> = {}
for (const [key, value] of Object.entries(data)) {
if (known.has(key)) result[key] = value
else log.warn("config key is not recognized and will be ignored", { key })
Comment on lines +445 to +454
Effect.catchCause((cause) =>
Effect.sync(() => {
const errors = cause.reasons
.filter(Cause.isDieReason)
.map((r) => (r.defect instanceof Error ? r.defect.name : "UnknownError"))
.join(", ")
log.error("invalid config: config file could not be parsed", { path: source, error: errors })
return {} as Info
}),
),
Comment on lines +642 to +651
it.instance("handles plugin resolution failure gracefully", () =>
Effect.gen(function* () {
const test = yield* TestInstance
yield* writeConfigEffect(test.directory, {
$schema: "https://opencode.ai/config.json",
model: "has-plugin",
plugin: ["./non-existent-plugin.ts"],
})
const config = yield* Config.use.get()
expect(config.model).toBe("has-plugin")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants